package analisador_PEWS;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import bean.MetodosPEWSXML;
import bean.MetodosServicos;

public class AnalisadorWSDL {
	private HashMap<String, String> aliasServicosEwsdl;
	private List<MetodosPEWSXML> listMetodosPEWS;
	private List<MetodosServicos> listMetodosServico;
	private Element elem;

	public AnalisadorWSDL() {
		// TODO Auto-generated constructor stub
		this.listMetodosServico = new ArrayList<MetodosServicos>();
	}
	
	public AnalisadorWSDL(HashMap<String, String> aliasServicosEwsdl, List<MetodosPEWSXML> metodos){
		this.aliasServicosEwsdl = aliasServicosEwsdl;
		this.listMetodosPEWS = metodos;
		this.listMetodosServico = new ArrayList<MetodosServicos>();
	}
	
	public void analisar(){
		Iterator it = this.aliasServicosEwsdl.keySet().iterator();
		while(it.hasNext()){
            String key = it.next().toString();
            String wsdlUrl = this.aliasServicosEwsdl.get(key);	
            
            //System.out.println(key +": "+ wsdlUrl);   
            
    		String wsdlString = parseWsdlToString(wsdlUrl);
    		parseStringToXml(wsdlString);
    		//IOArquivo.salvarArquivo("wsdl.txt", wsdlString, false);
    		
    		for (MetodosPEWSXML alias : this.listMetodosPEWS) {
				if(alias.getAliaServico().equalsIgnoreCase(key)){
					//System.out.println("\nAlias Metodo: " + alias.getAlias() + " Metodo: " +  alias.getMetodo());
					funcoes(alias.getMetodo());
				}
			}
		}
		//metodos();
	}	
	
	public String getServiceName(String urlWsdl){
		//System.out.println(urlWsdl);
		parseStringToXml(urlWsdl);
		
		return serviceName();
		
	}
	
	/**
	 * Responsavel por obter as informa��es pertencendo ao node schema do arquivo XPEWS
	 * @param metodo
	 */
	public void funcoes(String metodo){
		NodeList nl = this.elem.getElementsByTagName( "schema" );
	    NodeList nod1 =  nl.item(0).getChildNodes();
	    
		for(int i=0; i<nod1.getLength();i++){
			Node nod = nod1.item(i);
			if(nod.getNodeType() == Node.ELEMENT_NODE && nod.getNodeType() != Node.TEXT_NODE){
				if(nod.getAttributes().getNamedItem("name").getNodeValue().startsWith(metodo) ){
					String metodoWsdl	= nod.getAttributes().getNamedItem("name").getNodeValue();
					getListadeNos(nod.getChildNodes(), metodoWsdl);
				}				
			}
		}
		
		//getInfoMetodos("");
	}
	
	public void getListadeNos(NodeList lista, String metodoWsdl){
		for(int i=0; i<lista.getLength();i++){
			Node nod = lista.item(i);
			if(nod.getNodeType() == Node.ELEMENT_NODE && nod.getNodeType() != Node.TEXT_NODE){
		    	if(nod.hasChildNodes()){
		    		getListadeNos(nod.getChildNodes(), metodoWsdl);
		    	} else {
		    		getNode(nod, metodoWsdl);
		    	}
			}
		}
	}

	public void getNode(Node no, String metodoWsdl){		
			for(int i=0; i<no.getAttributes().getLength();i=2){
				String tipo = no.getAttributes().item(i+1).getNodeValue().substring(4);
				String valor = no.getAttributes().item(i).getNodeValue();
				addMetodoServico(metodoWsdl, valor, tipo);
			}		
	}
	
	public void addMetodoServico(String metodoWsdl, String valor, String tipo){
		MetodosServicos metodoNovo = new MetodosServicos(metodoWsdl);
		if(this.listMetodosServico.size()==0){			
			metodoNovo.addArgumentosETipo(valor,tipo);
			metodoNovo.setServico(serviceName());
			this.listMetodosServico.add(metodoNovo);
			
		}else if(metodoWsdl.endsWith("Response")){
			//System.out.println(tipo + " " + valor);
			metodoReponse(metodoWsdl, tipo);
		}else if(!addArgumentos(metodoWsdl, valor, tipo)){
			//System.out.println(tipo + " " + valor);
			metodoNovo.addArgumentosETipo(valor,tipo);
			metodoNovo.setServico(serviceName());
			this.listMetodosServico.add(metodoNovo);
		}

	}
	
	public void metodoReponse(String metodoWsdl, String tipo){
		String nome = metodoWsdl.substring(0,metodoWsdl.length()-8);
		for(int i=0; i<this.listMetodosServico.size();i++){
			if(this.listMetodosServico.get(i).getMetodo().equalsIgnoreCase(nome)){
				//System.out.println(this.listMetodosServico.get(i).getMetodo());
				this.listMetodosServico.get(i).setRetorno(tipo);
				break;
			}
		}
	}
	
	public boolean addArgumentos(String metodoWsdl, String valor, String tipo){
		for(int i=0; i<this.listMetodosServico.size();i++){
			if(this.listMetodosServico.get(i).getMetodo().equalsIgnoreCase(metodoWsdl)){
				this.listMetodosServico.get(i).addArgumentosETipo(valor,tipo);
				return true;
			} 
		}
		return false;
	}
		
	/**
	 * Responsavel por obter as informações pertencendo nome do serviço
	 * @param metodo
	 */
	public String serviceName(){
		NodeList nl = this.elem.getElementsByTagName( "wsdl:service" );
		Node no = nl.item(0).getAttributes().getNamedItem("name");
		
		return no.getNodeValue().toString();
	}
	


	public  String parseWsdlToString(String wsdlUrl){        
		try {
			URL url = new URL(wsdlUrl);
	        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
	        BufferedReader input = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
	        StringBuilder sbuilder = new StringBuilder();
	        String linha = null;          
	        while( (linha = input.readLine()) != null ){
	        	sbuilder.append(linha + '\n');	        	
	        }        
	        input.close();
	        urlConnection.disconnect();
	        return sbuilder.toString();
		} catch (MalformedURLException e) {
			System.out.println("Erro MalformedURLException: "+e.getMessage()+"\n"+e.getCause()); 
		} catch (IOException e) {
			System.out.println("Erro IOException: "+e.getMessage()+"\t\t"+e.getCause()); 
		} 
		return null;
	}
	
	public void parseStringToXml(String wsdlUrl){
		String wsdlString = parseWsdlToString(wsdlUrl);
		
		DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
	    domFactory.setNamespaceAware(true);
	    DocumentBuilder docBuilder;
		try {
			docBuilder = domFactory.newDocumentBuilder();
		    InputSource is = new InputSource( new StringReader(wsdlString));
		    Document doc = docBuilder.parse(is);
		    this.elem = doc.getDocumentElement();
		} catch (ParserConfigurationException e) {
			System.out.println("Arquivo nao foi encontrado" + e.getMessage());
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("Arquivo nao foi encontrado" + e.getMessage());
		}

	}


	public void getInfoMetodos(String metodo){
		System.out.println("\n Imprimindo os Metodos");
		for (MetodosServicos l : this.listMetodosServico) {
			//if(l.getMetodo().equalsIgnoreCase(metodo)){
				System.out.println("Metodo: " + l.getMetodo() + " Argumentos: " + l.getArgumentosTipos()  + " Retorno: " + l.getRetorno() + " Servico: " + l.getServico());
			//}			
		}
	}
	
	public List<String> getArgumento(String metodo){
		for (MetodosServicos l : this.listMetodosServico) {
			if(l.getMetodo().equalsIgnoreCase(metodo)){
				return l.getArgumentos();
			}			
		}
		return null;
	}
	
	public List<String> getTipoArgumento(String metodo){
		for (MetodosServicos l : this.listMetodosServico) {
			if(l.getMetodo().equalsIgnoreCase(metodo)){
				return l.getTipodosArgumentos();
			}			
		}
		return null;
	}
	
	public String getTipoRetorno(String metodo){
		for (MetodosServicos l : this.listMetodosServico) {
			if(l.getMetodo().equalsIgnoreCase(metodo)){
				return l.getRetorno();
			}			
		}
		return null;
	}
}
